#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <stdint.h>

#define CRYPT_SHA2_256_BLOCKSIZE  64
#define CRYPT_SHA2_256_DIGESTSIZE 32
#define CRYPT_SHA2_512_BLOCKSIZE  128
#define CRYPT_SHA2_512_DIGESTSIZE 64

// 外部函数声明
void SHA256CompressMultiBlocks(uint32_t hash[8], const uint8_t *in, uint32_t num);
void SHA256CompressMultiBlocksWithZbb(uint32_t hash[8], const uint8_t *in, uint32_t num);
void SHA512CompressMultiBlocks(uint64_t hash[8], const uint8_t *in, uint32_t num);
void SHA512CompressMultiBlocksWithZbb(uint64_t hash[8], const uint8_t *in, uint64_t num);

// 获取高精度时间戳（微秒）
static double get_time_us(void) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000.0 + tv.tv_usec;
}

// 初始化SHA256的初始哈希值
static void init_sha256_state(uint32_t state[8]) {
    state[0] = 0x6a09e667UL;
    state[1] = 0xbb67ae85UL;
    state[2] = 0x3c6ef372UL;
    state[3] = 0xa54ff53aUL;
    state[4] = 0x510e527fUL;
    state[5] = 0x9b05688cUL;
    state[6] = 0x1f83d9abUL;
    state[7] = 0x5be0cd19UL;
}

// 初始化SHA512的初始哈希值
static void init_sha512_state(uint64_t state[8]) {
    state[0] = 0x6a09e667f3bcc908ULL;
    state[1] = 0xbb67ae8584caa73bULL;
    state[2] = 0x3c6ef372fe94f82bULL;
    state[3] = 0xa54ff53a5f1d36f1ULL;
    state[4] = 0x510e527fade682d1ULL;
    state[5] = 0x9b05688c2b3e6c1fULL;
    state[6] = 0x1f83d9abfb41bd6bULL;
    state[7] = 0x5be0cd19137e2179ULL;
}

// SHA256 C实现性能测试
static void performance_test_sha256_c(uint32_t num_blocks, uint32_t iterations) {
    uint32_t state[8];
    uint8_t *test_data;
    double start_time, end_time, total_time;
    double throughput_mbps;
    uint64_t total_bytes;

    size_t data_size = num_blocks * CRYPT_SHA2_256_BLOCKSIZE;
    test_data = malloc(data_size);
    if (!test_data) {
        printf("内存分配失败\n");
        return;
    }

    // 填充测试数据
    for (size_t i = 0; i < data_size; i++) {
        test_data[i] = (uint8_t)(i & 0xFF);
    }

    printf("SHA256 C实现测试参数:\n");
    printf("  块数量: %u\n", num_blocks);
    printf("  迭代次数: %u\n", iterations);
    printf("  数据大小: %zu 字节 (%.2f KB)\n", data_size, data_size / 1024.0);

    // 预热
    init_sha256_state(state);
    SHA256CompressMultiBlocks(state, test_data, num_blocks);

    // 开始性能测试
    start_time = get_time_us();
    for (uint32_t i = 0; i < iterations; i++) {
        init_sha256_state(state);
        SHA256CompressMultiBlocks(state, test_data, num_blocks);
    }
    end_time = get_time_us();
    total_time = end_time - start_time;

    total_bytes = (uint64_t)data_size * iterations;
    throughput_mbps = (total_bytes / (1024.0 * 1024.0)) / (total_time / 1000000.0);

    printf("SHA256 C实现性能结果:\n");
    printf("  总时间: %.2f 毫秒\n", total_time / 1000.0);
    printf("  平均每次: %.2f 微秒\n", total_time / iterations);
    printf("  总处理数据: %.2f MB\n", total_bytes / (1024.0 * 1024.0));
    printf("  吞吐量: %.2f MB/s\n", throughput_mbps);
    printf("  每块平均时间: %.2f 纳秒\n", (total_time * 1000.0) / (num_blocks * iterations));

    free(test_data);
}

// SHA256 汇编实现性能测试
static void performance_test_sha256_asm(uint32_t num_blocks, uint32_t iterations) {
    uint32_t state[8];
    uint8_t *test_data;
    double start_time, end_time, total_time;
    double throughput_mbps;
    uint64_t total_bytes;

    size_t data_size = num_blocks * CRYPT_SHA2_256_BLOCKSIZE;
    test_data = malloc(data_size);
    if (!test_data) {
        printf("内存分配失败\n");
        return;
    }

    // 填充测试数据
    for (size_t i = 0; i < data_size; i++) {
        test_data[i] = (uint8_t)(i & 0xFF);
    }

    printf("SHA256 汇编实现测试参数:\n");
    printf("  块数量: %u\n", num_blocks);
    printf("  迭代次数: %u\n", iterations);
    printf("  数据大小: %zu 字节 (%.2f KB)\n", data_size, data_size / 1024.0);

    // 预热
    init_sha256_state(state);
    SHA256CompressMultiBlocksWithZbb(state, test_data, num_blocks);

    // 开始性能测试
    start_time = get_time_us();
    for (uint32_t i = 0; i < iterations; i++) {
        init_sha256_state(state);
        SHA256CompressMultiBlocksWithZbb(state, test_data, num_blocks);
    }
    end_time = get_time_us();
    total_time = end_time - start_time;

    total_bytes = (uint64_t)data_size * iterations;
    throughput_mbps = (total_bytes / (1024.0 * 1024.0)) / (total_time / 1000000.0);

    printf("SHA256 汇编实现性能结果:\n");
    printf("  总时间: %.2f 毫秒\n", total_time / 1000.0);
    printf("  平均每次: %.2f 微秒\n", total_time / iterations);
    printf("  总处理数据: %.2f MB\n", total_bytes / (1024.0 * 1024.0));
    printf("  吞吐量: %.2f MB/s\n", throughput_mbps);
    printf("  每块平均时间: %.2f 纳秒\n", (total_time * 1000.0) / (num_blocks * iterations));

    free(test_data);
}

// SHA512 C实现性能测试
static void performance_test_sha512_c(uint32_t num_blocks, uint32_t iterations) {
    uint64_t state[8];
    uint8_t *test_data;
    double start_time, end_time, total_time;
    double throughput_mbps;
    uint64_t total_bytes;

    size_t data_size = num_blocks * CRYPT_SHA2_512_BLOCKSIZE;
    test_data = malloc(data_size);
    if (!test_data) {
        printf("内存分配失败\n");
        return;
    }

    // 填充测试数据
    for (size_t i = 0; i < data_size; i++) {
        test_data[i] = (uint8_t)(i & 0xFF);
    }

    printf("SHA512 C实现测试参数:\n");
    printf("  块数量: %u\n", num_blocks);
    printf("  迭代次数: %u\n", iterations);
    printf("  数据大小: %zu 字节 (%.2f KB)\n", data_size, data_size / 1024.0);

    // 预热
    init_sha512_state(state);
    SHA512CompressMultiBlocks(state, test_data, num_blocks);

    // 开始性能测试
    start_time = get_time_us();
    for (uint32_t i = 0; i < iterations; i++) {
        init_sha512_state(state);
        SHA512CompressMultiBlocks(state, test_data, num_blocks);
    }
    end_time = get_time_us();
    total_time = end_time - start_time;

    total_bytes = (uint64_t)data_size * iterations;
    throughput_mbps = (total_bytes / (1024.0 * 1024.0)) / (total_time / 1000000.0);

    printf("SHA512 C实现性能结果:\n");
    printf("  总时间: %.2f 毫秒\n", total_time / 1000.0);
    printf("  平均每次: %.2f 微秒\n", total_time / iterations);
    printf("  总处理数据: %.2f MB\n", total_bytes / (1024.0 * 1024.0));
    printf("  吞吐量: %.2f MB/s\n", throughput_mbps);
    printf("  每块平均时间: %.2f 纳秒\n", (total_time * 1000.0) / (num_blocks * iterations));

    free(test_data);
}

// SHA512 汇编实现性能测试
static void performance_test_sha512_asm(uint32_t num_blocks, uint32_t iterations) {
    uint64_t state[8];
    uint8_t *test_data;
    double start_time, end_time, total_time;
    double throughput_mbps;
    uint64_t total_bytes;

    size_t data_size = num_blocks * CRYPT_SHA2_512_BLOCKSIZE;
    test_data = malloc(data_size);
    if (!test_data) {
        printf("内存分配失败\n");
        return;
    }

    // 填充测试数据
    for (size_t i = 0; i < data_size; i++) {
        test_data[i] = (uint8_t)(i & 0xFF);
    }

    printf("SHA512 汇编实现测试参数:\n");
    printf("  块数量: %u\n", num_blocks);
    printf("  迭代次数: %u\n", iterations);
    printf("  数据大小: %zu 字节 (%.2f KB)\n", data_size, data_size / 1024.0);

    // 预热
    init_sha512_state(state);
    SHA512CompressMultiBlocksWithZbb(state, test_data, num_blocks);

    // 开始性能测试
    start_time = get_time_us();
    for (uint32_t i = 0; i < iterations; i++) {
        init_sha512_state(state);
        SHA512CompressMultiBlocksWithZbb(state, test_data, num_blocks);
    }
    end_time = get_time_us();
    total_time = end_time - start_time;

    total_bytes = (uint64_t)data_size * iterations;
    throughput_mbps = (total_bytes / (1024.0 * 1024.0)) / (total_time / 1000000.0);

    printf("SHA512 汇编实现性能结果:\n");
    printf("  总时间: %.2f 毫秒\n", total_time / 1000.0);
    printf("  平均每次: %.2f 微秒\n", total_time / iterations);
    printf("  总处理数据: %.2f MB\n", total_bytes / (1024.0 * 1024.0));
    printf("  吞吐量: %.2f MB/s\n", throughput_mbps);
    printf("  每块平均时间: %.2f 纳秒\n", (total_time * 1000.0) / (num_blocks * iterations));

    free(test_data);
}

int main(int argc, char *argv[]) {
    printf("SHA2 算法性能对比测试 (RISC-V 64位)\n");
    printf("=====================================\n\n");

    // 更全面的测试场景
    struct {
        uint32_t blocks;
        uint32_t iterations;
        const char *description;
        const char *use_case;
    } test_cases[] = {
        // 基础性能测试
        {1, 10000, "单块高频测试", "文件完整性校验、小消息认证"},
        {4, 2500, "小数据块测试", "网络包校验、短文本哈希"},
        {16, 625, "中等数据块测试", "页面级数据校验"},
        {64, 156, "大数据块测试", "文件块校验"},
        {256, 39, "超大数据块测试", "大文件分块处理"},
        
        // 吞吐量测试（固定总数据量约 1MB）
        {1, 16384, "最大吞吐量测试-单块", "极限单块处理能力"},
        {8, 2048, "最大吞吐量测试-8块", "适中批量处理"},
        {32, 512, "最大吞吐量测试-32块", "大批量处理"},
        {128, 128, "最大吞吐量测试-128块", "超大批量处理"},
        {1024, 16, "最大吞吐量测试-1024块", "极限批量处理"},
        
        // 实际应用场景测试
        {2, 5000, "TLS握手场景", "TLS证书链验证"},
        {8, 1250, "区块链场景", "区块哈希计算"},
        {32, 312, "文件系统场景", "大文件完整性校验"},
        {1, 50000, "密码验证场景", "用户密码哈希验证"},
        {512, 20, "数据库场景", "大记录完整性校验"},
        
        // 边界和压力测试
        {1, 100000, "单块极限测试", "测试函数调用开销"},
        {10000, 1, "大块极限测试", "测试内存带宽限制"},
        {100, 1000, "平衡负载测试", "CPU和内存平衡测试"},
        
        // 缓存友好性测试
        {8, 8000, "L1缓存友好测试", "数据在L1缓存内"},
        {128, 500, "L2缓存友好测试", "数据在L2缓存内"},
        {2048, 32, "L3缓存测试", "数据在L3缓存内"},
        {8192, 8, "内存带宽测试", "超出缓存容量"},
        
        // 功耗效率测试（较长时间运行）
        {64, 1000, "功耗效率测试", "持续运行功耗测试"},
        {16, 4000, "热稳定性测试", "长时间运行稳定性"},
    };

    // 添加性能对比汇总
    typedef struct {
        double sha256_c_throughput;
        double sha256_asm_throughput;
        double sha512_c_throughput;
        double sha512_asm_throughput;
        const char *scenario;
    } perf_summary_t;

    perf_summary_t perf_results[sizeof(test_cases) / sizeof(test_cases[0])];

    for (size_t i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
        printf("=== 测试场景 %zu: %s ===\n", i + 1, test_cases[i].description);
        printf("应用场景: %s\n", test_cases[i].use_case);
        printf("参数: %u块 × %u次迭代\n\n", test_cases[i].blocks, test_cases[i].iterations);

        // 记录开始时间
        double scenario_start = get_time_us();

        printf("1. SHA256 C实现:\n");
        printf("----------------------------------------\n");
        double sha256_c_start = get_time_us();
        performance_test_sha256_c(test_cases[i].blocks, test_cases[i].iterations);
        double sha256_c_end = get_time_us();
        printf("\n");

        printf("2. SHA256 汇编实现 (Zbb):\n");
        printf("----------------------------------------\n");
        double sha256_asm_start = get_time_us();
        performance_test_sha256_asm(test_cases[i].blocks, test_cases[i].iterations);
        double sha256_asm_end = get_time_us();
        printf("\n");

        printf("3. SHA512 C实现:\n");
        printf("----------------------------------------\n");
        double sha512_c_start = get_time_us();
        performance_test_sha512_c(test_cases[i].blocks, test_cases[i].iterations);
        double sha512_c_end = get_time_us();
        printf("\n");

        printf("4. SHA512 汇编实现 (Zbb):\n");
        printf("----------------------------------------\n");
        double sha512_asm_start = get_time_us();
        performance_test_sha512_asm(test_cases[i].blocks, test_cases[i].iterations);
        double sha512_asm_end = get_time_us();
        printf("\n");

        // 计算性能提升比例
        uint64_t total_sha256_bytes = (uint64_t)test_cases[i].blocks * CRYPT_SHA2_256_BLOCKSIZE * test_cases[i].iterations;
        uint64_t total_sha512_bytes = (uint64_t)test_cases[i].blocks * CRYPT_SHA2_512_BLOCKSIZE * test_cases[i].iterations;
        
        double sha256_c_time = sha256_c_end - sha256_c_start;
        double sha256_asm_time = sha256_asm_end - sha256_asm_start;
        double sha512_c_time = sha512_c_end - sha512_c_start;
        double sha512_asm_time = sha512_asm_end - sha512_asm_start;

        double sha256_c_throughput = (total_sha256_bytes / (1024.0 * 1024.0)) / (sha256_c_time / 1000000.0);
        double sha256_asm_throughput = (total_sha256_bytes / (1024.0 * 1024.0)) / (sha256_asm_time / 1000000.0);
        double sha512_c_throughput = (total_sha512_bytes / (1024.0 * 1024.0)) / (sha512_c_time / 1000000.0);
        double sha512_asm_throughput = (total_sha512_bytes / (1024.0 * 1024.0)) / (sha512_asm_time / 1000000.0);

        // 保存结果用于最终汇总
        perf_results[i].sha256_c_throughput = sha256_c_throughput;
        perf_results[i].sha256_asm_throughput = sha256_asm_throughput;
        perf_results[i].sha512_c_throughput = sha512_c_throughput;
        perf_results[i].sha512_asm_throughput = sha512_asm_throughput;
        perf_results[i].scenario = test_cases[i].description;

        printf("📊 本场景性能对比:\n");
        printf("----------------------------------------\n");
        printf("SHA256: 汇编 vs C = %.2fx 提升 (%.2f vs %.2f MB/s)\n", 
               sha256_asm_throughput / sha256_c_throughput, 
               sha256_asm_throughput, sha256_c_throughput);
        printf("SHA512: 汇编 vs C = %.2fx 提升 (%.2f vs %.2f MB/s)\n", 
               sha512_asm_throughput / sha512_c_throughput, 
               sha512_asm_throughput, sha512_c_throughput);
        printf("SHA512 vs SHA256: C实现 = %.2fx (%.2f vs %.2f MB/s)\n",
               sha512_c_throughput / sha256_c_throughput,
               sha512_c_throughput, sha256_c_throughput);
        printf("SHA512 vs SHA256: 汇编实现 = %.2fx (%.2f vs %.2f MB/s)\n",
               sha512_asm_throughput / sha256_asm_throughput,
               sha512_asm_throughput, sha256_asm_throughput);

        double scenario_end = get_time_us();
        printf("本场景总耗时: %.2f 秒\n", (scenario_end - scenario_start) / 1000000.0);
        printf("==========================================\n\n");
    }

    // 最终性能汇总报告
    printf("\n🎯 最终性能汇总报告\n");
    printf("=========================================\n\n");

    // 找出最佳和最差场景
    double best_sha256_speedup = 0, worst_sha256_speedup = 999;
    double best_sha512_speedup = 0, worst_sha512_speedup = 999;
    size_t best_sha256_idx = 0, worst_sha256_idx = 0;
    size_t best_sha512_idx = 0, worst_sha512_idx = 0;

    printf("📈 各场景性能提升汇总:\n");
    printf("%-25s %12s %12s %12s %12s\n", 
           "场景", "SHA256提升", "SHA512提升", "SHA256吞吐", "SHA512吞吐");
    printf("%-25s %12s %12s %12s %12s\n", 
           "-----", "--------", "--------", "--------", "--------");

    for (size_t i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
        double sha256_speedup = perf_results[i].sha256_asm_throughput / perf_results[i].sha256_c_throughput;
        double sha512_speedup = perf_results[i].sha512_asm_throughput / perf_results[i].sha512_c_throughput;

        if (sha256_speedup > best_sha256_speedup) {
            best_sha256_speedup = sha256_speedup;
            best_sha256_idx = i;
        }
        if (sha256_speedup < worst_sha256_speedup) {
            worst_sha256_speedup = sha256_speedup;
            worst_sha256_idx = i;
        }
        if (sha512_speedup > best_sha512_speedup) {
            best_sha512_speedup = sha512_speedup;
            best_sha512_idx = i;
        }
        if (sha512_speedup < worst_sha512_speedup) {
            worst_sha512_speedup = sha512_speedup;
            worst_sha512_idx = i;
        }

        // 截取场景名称前20个字符
        char short_name[26];
        snprintf(short_name, sizeof(short_name), "%.25s", perf_results[i].scenario);

        printf("%-25s %11.2fx %11.2fx %10.1f MB %10.1f MB\n",
               short_name, sha256_speedup, sha512_speedup,
               perf_results[i].sha256_asm_throughput,
               perf_results[i].sha512_asm_throughput);
    }

    printf("\n🏆 最佳性能场景:\n");
    printf("SHA256最佳提升: %.2fx - %s\n", best_sha256_speedup, perf_results[best_sha256_idx].scenario);
    printf("SHA512最佳提升: %.2fx - %s\n", best_sha512_speedup, perf_results[best_sha512_idx].scenario);

    printf("\n⚠️  最差性能场景:\n");
    printf("SHA256最小提升: %.2fx - %s\n", worst_sha256_speedup, perf_results[worst_sha256_idx].scenario);
    printf("SHA512最小提升: %.2fx - %s\n", worst_sha512_speedup, perf_results[worst_sha512_idx].scenario);

    // 计算平均性能提升
    double avg_sha256_speedup = 0, avg_sha512_speedup = 0;
    double max_sha256_throughput = 0, max_sha512_throughput = 0;
    for (size_t i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
        avg_sha256_speedup += perf_results[i].sha256_asm_throughput / perf_results[i].sha256_c_throughput;
        avg_sha512_speedup += perf_results[i].sha512_asm_throughput / perf_results[i].sha512_c_throughput;
        if (perf_results[i].sha256_asm_throughput > max_sha256_throughput) {
            max_sha256_throughput = perf_results[i].sha256_asm_throughput;
        }
        if (perf_results[i].sha512_asm_throughput > max_sha512_throughput) {
            max_sha512_throughput = perf_results[i].sha512_asm_throughput;
        }
    }
    avg_sha256_speedup /= (sizeof(test_cases) / sizeof(test_cases[0]));
    avg_sha512_speedup /= (sizeof(test_cases) / sizeof(test_cases[0]));

    printf("\n📊 总体统计:\n");
    printf("SHA256 平均性能提升: %.2fx\n", avg_sha256_speedup);
    printf("SHA512 平均性能提升: %.2fx\n", avg_sha512_speedup);
    printf("SHA256 最大吞吐量: %.1f MB/s\n", max_sha256_throughput);
    printf("SHA512 最大吞吐量: %.1f MB/s\n", max_sha512_throughput);

    printf("\n💡 推荐使用场景:\n");
    if (best_sha256_speedup > 2.0) {
        printf("✅ SHA256汇编实现在 '%s' 场景下表现最佳\n", perf_results[best_sha256_idx].scenario);
    }
    if (best_sha512_speedup > 2.0) {
        printf("✅ SHA512汇编实现在 '%s' 场景下表现最佳\n", perf_results[best_sha512_idx].scenario);
    }
    if (worst_sha256_speedup < 1.5) {
        printf("⚠️  SHA256在 '%s' 场景下汇编优势不明显，可考虑使用C实现\n", perf_results[worst_sha256_idx].scenario);
    }
    if (worst_sha512_speedup < 1.5) {
        printf("⚠️  SHA512在 '%s' 场景下汇编优势不明显，可考虑使用C实现\n", perf_results[worst_sha512_idx].scenario);
    }

    return 0;
}